// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.

#include "ChangeMat.h"
#include "ChangeMatStyle.h"
#include "ChangeMatCommands.h"
#include "LevelEditor.h"
#include "Widgets/Docking/SDockTab.h"
#include "Widgets/Layout/SBox.h"
#include "Widgets/Text/STextBlock.h"
#include "Framework/MultiBox/MultiBoxBuilder.h"
#include "SChangeMatWidget.h"
#include "Misc/PackageName.h"
#include "AssetRegistryModule.h"
#include "SimpleINIBPLibrary.h"

static const FName ChangeMatTabName( TEXT( "ChangeMat" ) );

#define LOCTEXT_NAMESPACE "FChangeMatModule"

void FChangeMatModule::StartupModule()
{
	// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
	
	FChangeMatStyle::Initialize();
	FChangeMatStyle::ReloadTextures();

	FChangeMatCommands::Register();
	
	PluginCommands = MakeShareable(new FUICommandList);

	PluginCommands->MapAction(
		FChangeMatCommands::Get().OpenPluginWindow,
		FExecuteAction::CreateRaw(this, &FChangeMatModule::PluginButtonClicked),
		FCanExecuteAction());
		
	FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked<FLevelEditorModule>( TEXT( "LevelEditor" ) );
	
	{
		TSharedPtr<FExtender> MenuExtender = MakeShareable(new FExtender());
		MenuExtender->AddMenuExtension(TEXT("WindowLayout"), EExtensionHook::After, PluginCommands, FMenuExtensionDelegate::CreateRaw(this, &FChangeMatModule::AddMenuExtension));

		LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(MenuExtender);
	}
	
	{
		TSharedPtr<FExtender> ToolbarExtender = MakeShareable(new FExtender);
		ToolbarExtender->AddToolBarExtension(TEXT("Settings"), EExtensionHook::After, PluginCommands, FToolBarExtensionDelegate::CreateRaw(this, &FChangeMatModule::AddToolbarExtension));
		
		LevelEditorModule.GetToolBarExtensibilityManager()->AddExtender(ToolbarExtender);
	}
	
	FGlobalTabmanager::Get()->RegisterNomadTabSpawner(ChangeMatTabName, FOnSpawnTab::CreateRaw(this, &FChangeMatModule::OnSpawnPluginTab))
		.SetDisplayName(LOCTEXT("FChangeMatTabTitle", "ChangeMat"))
		.SetMenuType(ETabSpawnerMenuType::Hidden);
}

void FChangeMatModule::ShutdownModule()
{
	// This function may be called during shutdown to clean up your module.  For modules that support dynamic reloading,
	// we call this function before unloading the module.
	FChangeMatStyle::Shutdown();

	FChangeMatCommands::Unregister();

	FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(ChangeMatTabName);
}

TSharedRef<SDockTab> FChangeMatModule::OnSpawnPluginTab(const FSpawnTabArgs& SpawnTabArgs)
{
	//FText WidgetText = FText::Format(
	//	LOCTEXT("WindowWidgetText", "Add code to {0} in {1} to override this window's contents"),
	//	FText::FromString(TEXT("FChangeMatModule::OnSpawnPluginTab")),
	//	FText::FromString(TEXT("ChangeMat.cpp"))
	//	);

	//return SNew(SDockTab)
	//	.TabRole(ETabRole::NomadTab)
	//	[
	//		// Put your tab content here!
	//		SNew(SBox)
	//		.HAlign(HAlign_Center)
	//		.VAlign(VAlign_Center)
	//		[
	//			SNew(STextBlock)
	//			.Text(WidgetText)
	//		]
	//	];

	TSharedRef<SDockTab> NewTab = SNew( SDockTab )
		.TabRole( ETabRole::NomadTab )
	[
		SAssignNew( ChangeMatWidget, SChangeMatWidget )
		.OnOkButtonClicked( SChangeMatWidget::FOnOkButtonClicked::CreateRaw( this, &FChangeMatModule::UISubmited ) )
	];
	//NewTab->SetContent( SWidget* );

	return NewTab;
}

void FChangeMatModule::PluginButtonClicked()
{
	FGlobalTabmanager::Get()->InvokeTab(ChangeMatTabName);
}

void FChangeMatModule::AddMenuExtension(FMenuBuilder& Builder)
{
	Builder.AddMenuEntry(FChangeMatCommands::Get().OpenPluginWindow);
}

void FChangeMatModule::AddToolbarExtension(FToolBarBuilder& Builder)
{
	Builder.AddToolBarButton(FChangeMatCommands::Get().OpenPluginWindow);
}

void FChangeMatModule::UISubmited( const FString& Path, const FString& MatTemplatePath )
{
	FString LogFolder = FPaths::ProjectLogDir( );
	FString ResultLogFile = FPaths::Combine( LogFolder, TEXT( "ChangeMaterialResult.log" ) );
	USimpleINIBPLibrary::LoadIniFile( ResultLogFile, true );

	FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>( AssetRegistryConstants::ModuleName );
	IAssetRegistry& AssetReg = AssetRegistryModule.Get( );

	TArray<FAssetData> TemplateMatAssets;
	AssetReg.GetAssetsByPath( FName( *MatTemplatePath ), TemplateMatAssets, true );

	TMap<FName, UMaterialInterface*> TemplateMatMap;
	for (auto Iter( TemplateMatAssets.CreateIterator( ) ); Iter; ++Iter)
	{
		UObject* Obj = Iter->GetAsset( );
		if (Obj && Obj->IsA<UMaterialInterface>( ))
		{
			TemplateMatMap.Add( FName( *Obj->GetName( ) ), Cast<UMaterialInterface>( Obj ) );
		}
	}

	TMultiMap<UPackage*, UObject*> PackagesMap;

	TArray<FAssetData> Assets;
	AssetReg.GetAssetsByPath( FName( *Path ), Assets, true );
	for (auto Iter( Assets.CreateIterator( ) ); Iter; ++Iter)
	{
		UObject* Obj = Iter->GetAsset( );
		if (Obj && Obj->IsA<UStaticMesh>( ))
		{
			UStaticMesh* StaticMesh = Cast<UStaticMesh>( Obj );

			//static FName NAME_StaticMaterials = GET_MEMBER_NAME_CHECKED( UStaticMesh, StaticMaterials );

			bool bModified = false;
			for (int MatIndex = 0; true; MatIndex++)
			{
				UMaterialInterface* MatInterface = StaticMesh->GetMaterial( MatIndex );
				if (MatInterface)
				{
					FName MatName = *MatInterface->GetName( );
					//FName MatName = StaticMesh->StaticMaterials[MatIndex].MaterialSlotName;
					UMaterialInterface** ppMat = TemplateMatMap.Find( MatName );
					if (ppMat)
					{
						FString Path0 = MatInterface->GetPathName( );
						FString Path1 = (*ppMat)->GetPathName( );
						if (Path0 != Path1)
						{
							StaticMesh->SetMaterial( MatIndex, *ppMat );
							bModified = true;
							USimpleINIBPLibrary::SetValue( ResultLogFile, StaticMesh->GetPathName( ), MatName.ToString( ), TEXT( "Success" ) );
						}
						else
						{
							USimpleINIBPLibrary::SetValue( ResultLogFile, StaticMesh->GetPathName( ), MatName.ToString( ), TEXT( "Unchange" ) );
						}
					}
					else
					{
						USimpleINIBPLibrary::SetValue( ResultLogFile, StaticMesh->GetPathName( ), MatName.ToString( ), TEXT( "Failure" ) );
					}
				}
				else
				{
					break;
				}
			}

			if (bModified)
			{
				UPackage* Package = Iter->GetPackage( );
				Package->MarkPackageDirty( );
				PackagesMap.Add( Package, Obj );
			}
		}
	}

	//for (int32 i = 0; i < Packages.Num( ); ++i)
	//{
		/*FString PackageFileName = FPackageName::LongPackageNameToFilename( Packages[i]->GetP, FPackageName::GetAssetPackageExtension( ) );
		UPackage::Save( Packages[i], NewTexture, EObjectFlags::RF_Public | EObjectFlags::RF_Standalone, *PackageFileName, GError, nullptr, true, true, SAVE_NoError );
		Packages[i]->Save()*/
	//}

	USimpleINIBPLibrary::SaveIniFile( ResultLogFile, true );

	if (ChangeMatWidget)
	{
		ChangeMatWidget->ShowLog( ResultLogFile );
	}
}

#undef LOCTEXT_NAMESPACE
	
IMPLEMENT_MODULE(FChangeMatModule, ChangeMat)